
#include <stdio.h>
#include <string.h>

const char* types[] = {"Decimal",
                       "Int64",
                       "Int32",
                       "Int16",
                       "SByte",
                       "UInt64",
                       "UInt32",
                       "UInt16",
                       "Byte",
                       "Single",
                       "Double",
                       "Object"};

void write_definition(FILE* fo, const char* name, const char* type)
{
    fprintf(fo,
            "    Public Function %s(ByRef i As %s, Optional ByVal j As %s = 1) As %s\n",
            name,
            type,
            type,
            type);
}

void write_end_function(FILE* fo)
{
    fputs("    End Function\n\n", fo);
}

void write_pre_operator(FILE* fo, const char op)
{
    fprintf(fo,
            "        i %c= j\n"
            "        Return i\n",
            op);
}

void write_after_operator(FILE* fo, const char op, const char* type)
{
    fprintf(fo,
            "        Dim o As %s = ",
            type);
    if(strcmp(type, "Object") == 0)
        fprintf(fo,
            "Nothing\n"
            "        copy(o, i)");
    else
        fprintf(fo,
            "0\n"
            "        o = i");
    fprintf(fo,
            "\n"
            "        i %c= j\n"
            "        Return o\n",
            op);
}

void write_non_order_operator(FILE* fo, const char* name, const char* type)
{
    write_definition(fo, name, type);
    fprintf(fo,
            "        Return _%s(i, j)\n",
            name);
    write_end_function(fo);
}

void write_generic(FILE* fo, const char* name)
{
    fprintf(fo,
            "    Public Function %s(Of T)(ByRef i As T, ByVal j As T) As T\n"
            "         i = cast(Of T)(%s(cast(Of Object)(i), cast(Of Object)(j)))\n"
            "         Return i\n",
            name,
            name);
    write_end_function(fo);
}

int main(int argc, char* argv[])
{
    if(argc < 2) printf("need a parameter for output file.\n");
    else
    {
        const char* _inc = "_inc";
        const char* _dec = "_dec";
        const char* inc_ = "inc_";
        const char* dec_ = "dec_";
        const char* inc = "inc";
        const char* dec = "dec";

        FILE* fo = fopen(argv[1], "w");
        fputs("\n'this file is generated by osi/root/codegen/++--/++--.exe"
              "\n'so edit the osi/root/codegen/++--/++--.cpp instead of this file\n"
              "\nImports osi.root.connector\n\nPublic Module ____\n\n", fo);
        for(int i = 0; i < sizeof(types) / sizeof(types[0]); i++)
        {
            write_definition(fo, _inc, types[i]);
            write_pre_operator(fo, '+');
            write_end_function(fo);

            write_definition(fo, _dec, types[i]);
            write_pre_operator(fo, '-');
            write_end_function(fo);

            write_definition(fo, inc_, types[i]);
            write_after_operator(fo, '+', types[i]);
            write_end_function(fo);

            write_definition(fo, dec_, types[i]);
            write_after_operator(fo, '-', types[i]);
            write_end_function(fo);

            write_non_order_operator(fo, inc, types[i]);
            write_non_order_operator(fo, dec, types[i]);
        }

        write_generic(fo, _inc);
        write_generic(fo, _dec);
        write_generic(fo, inc_);
        write_generic(fo, dec_);
        write_generic(fo, inc);
        write_generic(fo, dec);

        fputs("End Module\n", fo);
        fclose(fo);
    }
}
